﻿
using System;

namespace SharpDepend.Datatypes
{
    /// <summary>
    /// Texture that contains pixels in a array for displaying for several platfomrs.
    /// <para>This can be used for Hardware and Software renderer.</para>
    /// </summary>
    public sealed class Texture
    {
        private volatile static int sID;

        public int ID
        {
            get; private set;
        }

        public event Action<Texture> OnBeginUpdate;

        public event Action<Texture> OnEndUpdate;

        /// <summary>
        /// Get pixel arrays.
        /// </summary>
        public int[] Data { get; private set; }

        /// <summary>
        /// Get width of texture.
        /// </summary>
        public int Width { get; private set; }

        /// <summary>
        /// Get height of texture.
        /// </summary>
        public int Height { get; private set; }

        public Vector4 Dimension { get; private set; }

        /// <summary>
        /// Create a texture by given width and height.
        /// </summary>
        /// <param name="width">Width in pixels.</param>
        /// <param name="height">Height in pixels.</param>
        public Texture(int width, int height)
        {
            ID = sID++;

            Width = width;
            Height = height;
            Data = new int[width * height];

            Dimension = new Vector4(0, 0, width, height);
        }

        /// <summary>
        /// Create a texture by given width, height and custom back buffer.
        /// </summary>
        /// <param name="width">Width in pixels.</param>
        /// <param name="height">Height in pixels.</param>
        /// <param name="backBuffer">Custom back buffer instance.</param>
        public Texture(int width, int height, int[] backBuffer)
        {
            ID = sID++;

            Set(width, height, backBuffer);

            Dimension = new Vector4(0, 0, width, height);
        }

        public void Set(int width, int height, int[] backBuffer)
        {
            Width = width;
            Height = height;
            Data = backBuffer;

            Dimension = new Vector4(0, 0, width, height);
        }

        public void TestGenerate()
        {
            Color color = Color.Black;
            for (int i = 0; i < Data.Length; i++)
            {
                color.R = (byte)(i * 102660.9);
                color.G = (byte)(i * 13463.7);
                color.B = (byte)(i * 1634630.4);
                Data[i] = (int)color.Packet;
            }
        }

        public Texture Rescale(int newWidth, int newHeight)
        {
            Texture rescaled = new Texture(newWidth, newHeight);

            RescaleAlgorithm(rescaled);

            return rescaled;
        }

        public void Rescale(Texture destination)
        {
            RescaleAlgorithm(destination);
        }

        private void RescaleAlgorithm(Texture destination)
        {
            for (int y = destination.Height - 1; y >= 0; y--)
            {
                for (int x = destination.Width - 1; x >= 0; x--)
                {
                    int xA = (int)(Width / (double)destination.Width * x);
                    int yA = (int)(Height / (double)destination.Height * y);
                    int iA = y * destination.Width + x;
                    int iB = yA * Width + xA;

                    if (iA >= 0 && iA < destination.Data.Length && iB >= 0 && iB < Data.Length)
                    {
                        destination.Data[iA] = Data[iB];
                    }
                }
            }
        }

        public bool IsPowerOfTwo
        {
            get
            {
                return (Width & (Width - 1)) == 0 && (Height & (Height - 1)) == 0;
            }
        }

        public Texture Clone()
        {
            Texture cloned = new Texture(Width, Height);

            cloned.ID = ID;
            Array.Copy(Data, cloned.Data, Data.Length);

            return cloned;
        }

        public override string ToString()
        {
            return ID + " - width:" + Width + ", height: " + Height;
        }

        /// <summary>
        /// This will raise the OnCall event to trigger that this texture has been updated.
        /// <para>For example OpenGL/ES can catch that event to update the texture for display.</para>
        /// </summary>
        public void BeginUpdate()
        {
            var call = OnBeginUpdate;
            if (call != null)
            {
                call(this);
            }
        }
        /// <summary>
        /// This will raise the OnCall event to trigger that this texture has been updated.
        /// <para>For example OpenGL/ES can catch that event to update the texture for display.</para>
        /// </summary>
        public void EndUpdate()
        {
            var call = OnEndUpdate;
            if (call != null)
            {
                call(this);
            }
        }
    }
}
